﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OVS_FormsRecognition.Manager;
using System.Windows.Controls;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using System.IO;
using OVS.BLL;
using OVS.BusinessObjects;
using System.Diagnostics;

namespace OVS_VideoRecorder.Manager
{
    public class VideoRecorderManager
    {
        #region attributs
        private double fps;
        private double fourcc;
        private bool exist;
        private List<VideoWriterAlert> listVidWriter;
        #endregion

        /// <summary>
        /// Logger par défaut du ManagerUtilisateurs
        /// </summary>
        private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(typeof(VideoRecorderManager));

        #region Gestion du singleton

        /// <summary>
        /// Instance locale pour héberger le singleton
        /// </summary>
        static VideoRecorderManager instance = null;

        /// <summary>
        /// Objet permettant la gestion des LOCK lors de l'instanciation
        /// </summary>
        static readonly object padlock = new object();

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        VideoRecorderManager()
        {
            if (_Log.IsDebugEnabled)
                _Log.DebugFormat("Nouvelle instance de '{0}'", this.GetType().ToString());
            exist = false;
            listVidWriter = new List<VideoWriterAlert>();
        }

        /// <summary>
        /// Déclaration unique par gestion du singleton
        /// </summary>
        public static VideoRecorderManager Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new VideoRecorderManager();
                    }
                    return instance;
                }
            }
        }

        #endregion Gestion du singleton


        /// <summary>
        /// Registers the event handler.
        /// </summary>
        /// <param name="pSizeCalculationStartEvent">The p size calculation start event.</param>
        public void registerEventHandler()
        {
            FormsRecognitionManager.Instance.VideoRecorderEventNewFrame += new FormsRecognitionManager.VideoRecorderEventHandler(CallbackVideoRecorderEventNewFrame);
            FormsRecognitionManager.Instance.VideoRecorderEventStopSaveVideo += new FormsRecognitionManager.VideoRecorderEventHandler(CallBackVideoRecorderEventStopSaveVideo);

        }

        /// <summary>
        /// Calls the back size calculation start event.
        /// </summary>
        /// <param name="nullObject">The null object.</param>
        /// <param name="pSizeCalculationEventArgs">The <see cref="SizeCalculationEventArgs" /> instance containing the event data.</param>
        private void CallbackVideoRecorderEventNewFrame(object nullObject, VideoRecorderEventArgs pSizeCalculationEventArgs)
        {
            lock (padlock)
            {
                _Log.Debug("new event pVideoRecorderEventNewFrame id_alert: {0} " + pSizeCalculationEventArgs.id_alert);

                exist = false;

                try
                {
                    Image<Bgr, byte> ImageFrame = pSizeCalculationEventArgs.ImageFrame;

                    foreach (VideoWriterAlert vWA in listVidWriter)
                    {
                        if (vWA.alertID == pSizeCalculationEventArgs.id_alert)
                        {
                            vWA.addImg(ImageFrame);
                            exist = true;
                        }
                    }
                    if (!exist)
                    {
                        VideoWriterAlert wAlert = new VideoWriterAlert(pSizeCalculationEventArgs.id_alert);
                        //wAlert.AlertID = pSizeCalculationEventArgs.id_alert;
                        //wAlert.VWrit = new List<Image<Bgr, Byte>>();
                        wAlert.addImg(ImageFrame);
                        listVidWriter.Add(wAlert);
                    }
                }
                catch (Exception e)
                {
                    System.Windows.MessageBox.Show("CallbackVideoRecorderEventNewFrame: " + e.Message);
                }
            }

        }

        /// <summary>
        /// Calls the back size calculation start event.
        /// </summary>
        /// <param name="nullObject">The null object.</param>
        /// <param name="pSizeCalculationEventArgs">The <see cref="SizeCalculationEventArgs" /> instance containing the event data.</param>
        private void CallBackVideoRecorderEventStopSaveVideo(object nullObject, VideoRecorderEventArgs pSizeCalculationEventArgs)
        {

            lock (padlock)
            {
                _Log.Debug("new event ListenerVideoRecorderStartEvent !!!");

                int width = 0;
                int height = 0;

                //Convertit la vidéo avi en mp4 => utilisation de FFmpeg
                try
                {
                    foreach (VideoWriterAlert vwa in listVidWriter)
                    {
                        if (vwa.alertID == pSizeCalculationEventArgs.id_alert)
                        {
                            width = vwa.vWrit[0].Width;
                            height = vwa.vWrit[0].Height;
                            break;
                        }
                    }
                    //CvInvoke.CV_FOURCC('M', 'J', 'P', 'G')
                    VideoWriter vidWriter = new VideoWriter(@"C:\OVS\Videos\" + pSizeCalculationEventArgs.id_alert + ".avi", 2, width, height, true);
                    foreach (VideoWriterAlert vwa in listVidWriter)
                    {
                        if (vwa.alertID == pSizeCalculationEventArgs.id_alert)
                        {
                            for (int i = 0; i < vwa.vWrit.Count - 1; i++)
                            {
                                vidWriter.WriteFrame(vwa.vWrit[i]);
                            }
                            foreach (Image<Bgr, byte> tmpImg in vwa.vWrit)
                            {
                                tmpImg.Dispose();
                            }
                            vwa.vWrit.Clear();
                        }
                    }
                    vidWriter.Dispose();


                    Process Convert = new Process();
                    Convert.StartInfo = new ProcessStartInfo("ffmpeg", " -i " + "C:\\OVS\\Videos\\" + pSizeCalculationEventArgs.id_alert + ".avi" + " -f mp4 " + "C:\\OVS\\Videos\\" + pSizeCalculationEventArgs.id_alert + ".mp4");
                    Convert.StartInfo.CreateNoWindow = true;
                    Convert.StartInfo.RedirectStandardError = true;
                    Convert.StartInfo.RedirectStandardOutput = true;
                    Convert.StartInfo.UseShellExecute = false;
                    //Create the output and streamreader to get the output
                    string output = null; StreamReader srOutput = null;
                    try
                    {

                        Convert.Start();
                        srOutput = Convert.StandardError;
                        output = srOutput.ReadToEnd();
                        Convert.WaitForExit();
                        //get the output
                        
                        //now put it in a string
                        

                    }
                    catch (Exception)
                    {
                        output = string.Empty;

                    }
                    finally
                    {
                        Convert.Close();
                        //now, if we succeded, close out the streamreader
                        if (srOutput != null)
                        {
                            srOutput.Close();
                            srOutput.Dispose();
                        }
                    }

                    Alert alert = AlertBLL.Instance.GetAlert(pSizeCalculationEventArgs.id_alert);
                    //Insertion des videos dans la base
                    Video newVid = new Video();
                    newVid.vide_fn = @"C:\OVS\Videos\" + pSizeCalculationEventArgs.id_alert + ".mp4";
                    alert.vide_id = VideoBLL.Instance.AddVideo(newVid);
                    AlertBLL.Instance.UpdateAlert(alert);
                    //On vérifie que le fichier existe en mp4 avant de supprimer le .avi

                    if (File.Exists(@"C:\OVS\Videos\" + pSizeCalculationEventArgs.id_alert + ".mp4"))
                    {
                        File.Delete(@"C:\OVS\Videos\" + pSizeCalculationEventArgs.id_alert + ".avi");
                    }

                }
                catch (Exception e)
                {
                    _Log.Warn("VideoRecorderManager: Exeption: " + e);
                }
            }

        }

    }
}
